# -*- coding: utf-8 -*-
"""
    @Author ljy
    @Date 2020/11/4 17:26
    @Describe 会员（用户）模块
"""
import os
import uuid

from starlette.responses import JSONResponse

from dbs.securedao import SecureDao
from errors import JPGError, FileMaxSizeError
from mainapp import app
from typing import Optional
from fastapi import Query, Path, Body, Header, UploadFile, File, Depends
from dbs.userdao import UserDao
from dbs.caches import *
from mainapp.schema import UserInfo, RegistUser, FindPwd, PwdSecure
from settings import STATIC_DIR

# 用户登录
@app.get('/login',name='用户登录')
async def user_login_get(name:str = Query(...,min_length=4,max_length=20,regex=r'^[a-zA-Z+$]'),
                         pwd:str = Query(...,min_length=3,max_length=20) ):

    ret = UserDao().login(name,pwd)
    if ret:
        if not ret['is_active']:
            return {'msg':'当前用户未激活，请先激活用户','url':f'/active/{ret["id"]}'}

        ret['username'] = name
        ret['token'] = uuid.uuid4().hex
        # token和user_id 存到缓存中：待开发
        save_token(ret['token'],ret['id'])

        return {'msg':'登陆成功','data':ret}

    return {'msg':'登陆失败，用户名或口令错误','user': {
        'name':name,
        'pwd':pwd
    }}


# 状态激活
@app.get('/active/{user_id}',name='登录状态激活')
async def active_user(user_id:int = Path(...,ge=1)):
    ret = UserDao().get_user_active_state(user_id)
    if not ret:
        return {'msg':'激活的用户不存在，请确认你的用户ID'}
    elif ret['is_active']:
        return {'msg': '用户已激活，无需再次激活'}
    else:
        if UserDao().active(user_id):
                return {'msg':'用户激活成功，可以正常登录了'}

    return {'msg':'用户激活失败'}


# 修改（更新）用户信息
@app.put('/user',description='更新用户',name='更新用户')
async def update_user(token:Optional[str]=Header(...,title='请求头上的Token'),
                      user:UserInfo=Body(...)):
    if not has_token(token):
        return {'msg':'这是一个无效的token，请重新登陆'}
    user_id = int(get_user_id(token))
    if not UserDao().is_active(user_id):
        return {'msg':'当前用户状态异常，请联系管理员'}
    update_user = user.dict(exclude_unset=True)  # 有可能只更新某一项,exclude_unset=True只获取请求体中存在的信息
    update_user['id'] = user_id  # 更新sql语句的条件
    flag = UserDao().update_detail(**update_user)
    return {
        'msg':'用户更新成功' if flag else '用户更新失败'
    }


# 退出登录
@app.get('/logout',name='退出登录')
async  def logout(token:Optional[str] = Header(...)):
    remove_token(token)
    return {'msg':'用户退出成功！'}


# 注册时用户名的验证
@app.get('/checkname/{username}',name='注册时用户名验证')
async def check_username(username:Optional[str] = Path(...,min_length=4)):
    ret = UserDao().regist_check(username)
    return {
        'status':ret is None,
        'msg':'用户已存在' if ret else '用户名有效'
    }


# 用户注册
@app.post('/regist',name='注册')
async def regist_user(user:RegistUser=Body(...),
                      friend_code:Optional[str]=Query(None,title='邀请码')):
    # 1.验证两次口令是否相同
    if user.password != user.password2:
        return JSONResponse({'msg':'两次口令不相同'},205)
    # 2.保存用户信息
    user_info = user.dict(exclude_unset=True)
    user_info.pop('password2')
    # 修改password字段为auth_string
    user_info['auth_string'] = user_info.pop('password')
    user_id = UserDao().register(**user_info)   # 保存成功，返回保存之后的数据记录对象user_id
    token = uuid.uuid4().hex
    save_token(token,user_id)
    return {'msg':'注册成功！','token':token,
            'user':{'username':user_info['username'],
                    'nick_name':user_info.get('nick_name','')
                    }
            }


# 上传头像
@app.post('/avater',name='头像上传')
async def upload_user_avater(token:Optional[str] = Header(...),
                             headimg:UploadFile = File(...)):
    # 1.验证图片的大小和类型
    if headimg.content_type != 'image/jpeg':
        raise JPGError()
    content = await headimg.read()
    if len(content) > 2*1024*1024:
        raise FileMaxSizeError()

    # 保存文件
    user_id = get_user_id(token)
    filename = f'avaters/{user_id}.jpg'
    with open(os.path.join(STATIC_DIR,filename),'wb') as f:
        f.write(content)

    file_url = f'/s/{filename}'
    # 修改数据库
    UserDao().upload_avater(user_id, file_url)
    return {
        'msg':'用户头像上传成功',
        'path':f'/s/{filename}'
    }


@app.patch('/user',name='修改密码')
async def update_user_password(user:FindPwd):
    # 实现用户的口令修改或找回密码
    pass


async def secure_params(token:str=Header(...),
                         secure:PwdSecure=Body(...)):
    # 获取接口参数获取其他数据
    return {'uid':get_user_id(token),**secure.dict()}

async def get_dao():
    return SecureDao()


class SecureParams:
    def __init__(self,token:str=Header(...),secure:PwdSecure=Body(...)):
        self.dao = SecureDao()
        self.params = {'uid':get_user_id(token),**secure.dict()}


# @app.post('/secure',name='添加密保问题及答案')
# async def add_pwd_secure(params:dict = Depends(secure_params),
#                          dao:SecureDao = Depends(get_dao)):
#     # 添加问题及答案找回或修改密码
#     dao.add(**params)
#     return {'msg':'添加成功','data':params}

@app.post('/secure',name='添加密保问题及答案')
async def add_pwd_secure(data:SecureParams = Depends(SecureParams)):
    # 添加问题及答案找回或修改密码
    data.dao.add(**data.params)
    return {'msg':'添加成功','data':data.params}


@app.get('/secure', name='列举当前用户密保问题')
async def list_pwd_secure(token: str = Header(...)):
    # 查看当前用户的所有密保问题
    user_id = get_user_id(token)

    data = SecureDao().list(user_id)
    return {'msg': '查询成功','total':len(data),'data':data}


@app.put('/secure/{sid}', name='更改用户密保问题')
async def upd_pwd_secure(params=Depends(secure_params),
                         sid:int = Path(...),
                         dao=Depends(get_dao)):
    params['id']=sid
    dao.update(**params)
    return {'msg':'ok'}


@app.delete('/secure/{sid}', name='删除用户密保问题')
async def del_pwd_secure(token: str = Header(...),
                         sid:int = Path(...)):
    # 删除密保
    uid = get_user_id(token)
    if SecureDao().delete(id=sid,uid=uid) > 0:
       return {'msg':'删除成功'}
    return JSONResponse({'msg':'删除失败'},status_code=500)


# 上传或下载git某一个分支的语句